home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacHack 1997
/
MacHack 1997.toast
/
Hacks
/
Hacks ’96
/
Talking Telnet
/
source
/
network
/
network.c
< prev
next >
Wrap
Text File
|
1996-06-22
|
30KB
|
1,210 lines
/****************************************************************
* NCSA Telnet for the Macintosh *
* *
* National Center for Supercomputing Applications *
* Software Development Group *
* 152 Computing Applications Building *
* 605 E. Springfield Ave. *
* Champaign, IL 61820 *
* *
* Copyright (c) 1986-1993, *
* Board of Trustees of the University of Illinois *
*****************************************************************
* Revisions:
* 10/87 Initial source release, Tim Krauskopf
* 2/88 typedef support for other compilers (TK)
* 8/88 Gaige Paulsen - support for MacTCP drivers
* 1/89 TK - conversion to new drivers, minor update for new calling convention
* 6/89 TK - update to MacTCP 1.0 include files and use of GetMyIPAddr()
* 7/92 Scott Bulmahn - add support for 2 global structs, put cursors into an array
* 11/92 Jim Browne - Fixed more bugs than I care to mention.
*
*/
#ifdef MPW
#pragma segment Network
#endif
#include "InternalEvents.h"
#include "wind.h"
#include "maclook.proto.h"
#include "menuseg.proto.h"
#include "mainseg.proto.h"
#include "MyMacTCPstructures.h"
#include "network.proto.h"
#include "netevent.proto.h"
#include "tnae.h"
#include "authencrypt.h"
#include "authencrypt.proto.h"
#include "errors.proto.h"
#include "telneterrors.h"
#ifdef THINK_C
#pragma options(!profile)
#endif
#ifdef __MWERKS__
#pragma profile off
#endif
//#define NET_DEBUG_MUCHINFO
//#define NET_DEBUG
#ifdef NET_DEBUG
char net_debug_string[256];
#define net_debug_print(x) putln(net_debug_string)
#else
#define net_debug_print(x)
#endif
//PROTO_UPP(Notify, TCPNotify);
//static TCPIOCompletionProcPtr OpenCompleteInit(TCPiopb *pbp);
//PROTO_UPP(OpenCompleteInit, TCPIOCompletion);
//static TCPIOCompletionProcPtr CloseCompleteInit(TCPiopb *pbp);
//PROTO_UPP(CloseCompleteInit, TCPIOCompletion);
//static TCPIOCompletionProcPtr SendCompleteInit(TCPiopb *pbp);
//PROTO_UPP(SendCompleteInit, TCPIOCompletion);
static TCPIOCompletionUPP OpenCompleteInitUPP = nil;
static TCPIOCompletionUPP CloseCompleteInitUPP = nil;
static TCPIOCompletionUPP SendCompleteInitUPP = nil;
static TCPNotifyUPP NotifyUPP = nil;
static void OpenComplete(MyTCPpbPtr pbp);
static void SendComplete(MyTCPpbPtr pbp);
static void CloseComplete(MyTCPpbPtr pbp);
pascal void Notify(StreamPtr streamPtr, unsigned short code, Ptr uptr,
unsigned short terminReason, struct ICMPReport *icmpMsg);
static wdsEntry *getSWDS(void);
static void returnSWDS(wdsEntry *wds);
static void MyPBreturn(MyTCPpbPtr pbp);
static MyTCPpb *getPB(short driver,short call, StreamPtr stream, short usernum);
static void clearPB(MyTCPpbPtr pbp, short driver, short call, StreamPtr stream);
static OSErr xPBControlSync(MyTCPpbPtr pbp);
static OSErr xPBControlAsync(MyTCPpbPtr pbp, TCPIOCompletionUPP completionUPP);
static short makestream(void);
static void reclaim(StreamRPtr p);
static short giveback(StreamRPtr p, wdsEntry *wds);
static void compressfds(wdsEntry *fds);
static void NetWriteZero(Ptr pointer,long size); //put this here to keep from loading and unlaoding config segment
extern Cursor *theCursors[];
extern WindRec *screens;
long MyA5;
short TCPd = 0; /* refnum of TCP drivers */
QHdr gFreePBQueue;
QHdr gFreeSWDSQueue;
short numSWDS=0; /* Number of SWDS's ever alloc'd (PM Only) */
StreamRPtr streams[NPORTS];
ip_port nnfromport = 0;
Boolean nextIsUrgent = FALSE; //CCP 2.7 (See NetUrgent ())
void NetWriteZero(Ptr pointer,long size)
{
while (size--) *pointer++ = 0;
}
/**************************************************************************/
wdsEntry *getSWDS(void)
{
short n=0;
wdsEntry * wds;
if (gFreeSWDSQueue.qHead == NULL)
wds = (wdsEntry *) myNewPtrCritical( sizeof(wdsEntry) * MAX_SWDS_ELEMS);
else
{
wds = (wdsEntry *) gFreeSWDSQueue.qHead;
Dequeue(gFreeSWDSQueue.qHead, &gFreeSWDSQueue);
}
if (wds == NULL) { /* sorry, cant allocate WDS (BIG PROBLEM) */
DoError(508 | NET_ERRORCLASS, LEVEL3, NULL); // <- Is 508 correct?
forcequit();
// return ((wdsEntry*) 0L); <- ?? perhaps
}
return(wds);
}
/**************************************************************************/
void returnSWDS(wdsEntry *wds)
{
Enqueue((QElemPtr)wds, &gFreeSWDSQueue);
}
/**************************************************************************/
void MyPBreturn(MyTCPpbPtr pbp)
{
Enqueue((QElemPtr)pbp, &gFreePBQueue);
}
/**************************************************************************/
MyTCPpb *getPB(short driver,short call, StreamPtr stream, short usernum)
{
UNUSED_ARG(usernum)
MyTCPpb *pbp;
if (gFreePBQueue.qHead == NULL)
pbp = (MyTCPpbPtr) myNewPtrCritical( sizeof(MyTCPpb) );
else
{
pbp = (MyTCPpbPtr) gFreePBQueue.qHead;
Dequeue(gFreePBQueue.qHead, &gFreePBQueue);
}
if (pbp == NULL) { /* sorry, cant allocate TCP buffer (BIG PROBLEM) */
DoError(508 | NET_ERRORCLASS, LEVEL3, NULL);
forcequit();
}
memset((char *) pbp, '\0', sizeof(MyTCPpb));
pbp->pb.ioCRefNum = driver;
pbp->pb.tcpStream = stream;
pbp->pb.csCode = call;
return(pbp);
}
/**************************************************************************/
void clearPB(MyTCPpbPtr pbp, short driver, short call, StreamPtr stream)
{
NetWriteZero((Ptr)pbp, sizeof(MyTCPpb)); /* BYU LSC - Default to all zeros */
pbp->pb.ioCRefNum = driver;
pbp->pb.tcpStream = stream;
pbp->pb.csCode = call;
}
/**************************************************************************/
OSErr xPBControlSync(MyTCPpbPtr pbp)
{
pbp->pb.ioCompletion = 0L; /* Charlie will puke if he ever sees */
return PBControl((ParmBlkPtr)(pbp),false); /* his funtions here. -- JMB */
}
/**************************************************************************/
OSErr xPBControlAsync(MyTCPpbPtr pbp, TCPIOCompletionUPP completionUPP)
{
#ifndef __powerpc__
pbp->SavedA5 = MyA5;
#endif
pbp->pb.ioCompletion = completionUPP;
return(PBControl((ParmBlkPtr)(pbp),true)); /* async */
}
void SetPortType(short port, short type)
{
if (port >= 0 && port < NPORTS && (streams[port] != NULL))
streams[port]->portType = type;
}
short GetPortType(short port)
{
if (port >= 0 && port < NPORTS && (streams[port] != NULL))
return(streams[port]->portType);
else return(-1);
}
/**************************************************************************/
/* Returns an empty stream */
short makestream(void)
{
short pnum, i;
StreamRPtr p;
MyTCPpbPtr pbp;
for ( pnum=0; (streams[pnum]!= NULL) && pnum<NPORTS; pnum++)
; /* BYU 2.4.16 */
if (pnum >= NPORTS)
return(-2);
if (!(p = streams[pnum] = (StreamRPtr) myNewPtrCritical(sizeof(StreamRec))))
return(-1);
if ((p->buffer = (char *) myNewPtrCritical( TCPBUFSIZ)) == NULL) {
DisposePtr((Ptr)p);
streams[pnum] = 0;
return(-1);
}
if ((p->sbuffer = (char *) myNewPtrCritical( TCPBUFSIZ)) == NULL) {
DisposePtr((Ptr)p->buffer);
DisposePtr((Ptr)p);
streams[pnum] = 0;
return(-1);
}
for (i=0; i<MAX_FDS_ELEMS; i++)
{
p->fds[ i].length =0; p->fds[ i].ptr = 0L;
p->exFDS[ i].inuse=0; p->exFDS[ i].fds.length=0;p->exFDS[ i].fds.ptr=0L;
}
p->fds[0].length = TCPBUFSIZ;
p->fds[0].ptr = p->sbuffer;
p->maxFDSused=0;
p->aedata = NULL;
pbp=getPB( TCPd, TCPCreate, (long) 0, 7); /* BYU LSC important - Make create call */
pbp->pb.csParam.create.rcvBuff = p->buffer;
pbp->pb.csParam.create.rcvBuffLen = TCPBUFSIZ;
pbp->pb.csParam.create.notifyProc = NotifyUPP;
if (xPBControlSync(pbp) != noError)
DoError (512 | NET_ERRORCLASS, LEVEL2, NULL);
p->stream = pbp->pb.tcpStream;
net_debug_print("Made new stream");
MyPBreturn(pbp);
return(pnum);
}
/**************************************************************************/
/* reclaim( p) -
reclaims buffer space to stream (from pointer p) into the FDS list */
void reclaim(StreamRPtr p)
{
short n=0, offset=0;
while (offset < MAX_FDS_ELEMS && p->fds[offset].ptr != 0L) offset++;
if (offset >= MAX_FDS_ELEMS) /* offset too large -- cant reclaim */
return;
for (n=0 ; n<MAX_FDS_ELEMS && offset< MAX_FDS_ELEMS; n++)
{
if (p->exFDS[ n].inuse)
{
p->fds[ offset++]=p->exFDS[ n].fds;
p->exFDS[ n].inuse = 0;
}
}
}
/**************************************************************************
giveback( p, wds) - gives WDS entries back to the stream by putting them in the
mutually exclusive buffer.
p -> stream
wds -> wds array */
short giveback(StreamRPtr p, wdsEntry *wds)
{
short n=0, m=0;
while ( n< MAX_SWDS_ELEMS && wds[n].ptr !=0L)
{
while (m< MAX_FDS_ELEMS && p->exFDS[ m].inuse) m++;
if (m >= MAX_FDS_ELEMS) // This was off by one - JMB 2.6
return(-1); /* No room in the RECLAIMation center */
else
{
p->exFDS[ m].inuse =1;
p->exFDS[ m].fds = wds[n];
m++;
}
n++;
}
return 0;
}
/**************************************************************************/
/* compressfds( fds)
compress an fds data structure to make everyone happy */
void compressfds(wdsEntry *fds)
{
short n,m,compressed;
compressed = 0;
while ( !compressed) {
compressed=1;
for (n=0; n< MAX_FDS_ELEMS; n++)
{ /* Slow Forwards */
if (fds[n].ptr)
{ /* Do if N exists */
for ( m = MAX_FDS_ELEMS -1; m>=0; m--)
{ /* Fast Backwards */
if (fds[m].ptr && (fds[m].ptr+fds[m].length == fds[n].ptr)) {
fds[n].length+=fds[m].length;
fds[n].ptr = fds[m].ptr;
fds[m].ptr=0L;
fds[m].length=0;
compressed=0;
}
#ifdef CHECKBOTHWAYZ
else
if (fds[n].ptr+fds[n].length == fds[m].ptr)
{
fds[m].length+=fds[n].length;
fds[n].ptr=0L;
fds[n].length=0;
compressed=0;
}
#endif CHECKBOTHWAYZ
}
}
}
}
m=0;n=0;
/* Close the gaps */
while (n+m < MAX_FDS_ELEMS)
{
while (fds[n+m].ptr ==0L && n+m< MAX_FDS_ELEMS)
m++; /* increase gap to valid entry */
if (n+m<MAX_FDS_ELEMS)
fds[n]=fds[n+m];
n++;
}
/* Get rid of the empty spaces */
n--; /* for the next loop */
while (n < MAX_FDS_ELEMS)
{
fds[n].ptr=0;
fds[n++].length=0;
}
}
/***************************************************************************/
/* Mnetread
* Read from a connection buffer into a user buffer.
* Returns number of bytes read, < 0 on error
* NOTE:
* current version very inefficient, but hopefully works.
*/
short netread(short pnum, void *buffer, short n)
{
short i;
StreamRPtr p;
MyTCPpbPtr pbp;
short inQ, reqdamt;
if (pnum < 0 || pnum >= NPORTS) /* BYU 2.4.15 */
return(-2);
if (NULL == (p = streams[pnum]))
return(-2);
pbp=getPB( TCPd, TCPStatus, p->stream, 1); /* Make status call */
if (xPBControlSync(pbp) != noError) /* status call bombed */
DoError (509 | NET_ERRORCLASS, LEVEL1, "Mnetread");
if (pbp->pb.csParam.status.connectionState !=8) {
#ifdef NET_DEBUG
sprintf(net_debug_string, "CState: %d is %d",(int)pnum, (int)pbp->pb.csParam.status.connectionState);
net_debug_print(net_debug_string);
#endif
MyPBreturn(pbp);
return(-1); /* Connection not established */
}
inQ = pbp->pb.csParam.status.amtUnreadData;
reqdamt = n >inQ ? inQ : n;
clearPB( pbp, TCPd, TCPRcv, p->stream);
pbp->pb.csParam.receive.rcvBuff = buffer;
pbp->pb.csParam.receive.rcvBuffLen = reqdamt;
if (reqdamt<1)
{ /* Drop out if no data */
MyPBreturn(pbp);
return(0);
}
if ((i = xPBControlSync(pbp)) != noError) {
DoError (524 | NET_ERRORCLASS, LEVEL1, NULL);
return(-1);
}
reqdamt = pbp->pb.csParam.receive.rcvBuffLen;
if (reqdamt<inQ)
netputuev( CONCLASS, CONDATA, pnum,0); /* more data to get */
/* Decrypt data */
if (p->aedata && ((tnParams *)p->aedata)->decrypting) {
unsigned char *cp = (unsigned char *)buffer;
short len = reqdamt;
while (len-- > 0) {
*cp = decrypt((tnParams *)p->aedata, (long)(*cp));
cp++;
}
}
MyPBreturn(pbp);
return(reqdamt);
}
//makes the next buffer be sent as urgent data
void netUrgent(void)
{
nextIsUrgent = TRUE;
}
/************************************************************************/
/* netwrite
* write something into the output queue, netsleep routine will come
* around and send the data, etc.
*
*/
short netwrite(short pnum, void *buffer, short nsend)
{
StreamRPtr p;
wdsEntry *swds;
short remaining, queued, n,m;
MyTCPpbPtr pbp;
OSErr err;
#ifdef NET_DEBUG_MUCHINFO
sprintf(net_debug_string, "port: %d\tbuffer: %lx\tnsend %d", pnum,
(unsigned int)buffer, (int)nsend);
net_debug_print(net_debug_string);
#endif
if (pnum < 0 || pnum >= NPORTS) /* BYU 2.4.15 */
return(-2);
if ( (p = streams[pnum]) == NULL)
return(-2);
if ( !nsend )
return(0);
swds = getSWDS();
if (swds == NULL) return(nsend); // Duh, Mr. Bulmahn. - JMB 2.6
reclaim( p);
compressfds( p->fds);
n=0; remaining = nsend;
// if (p->fds[0].ptr == 0) DebugStr("\pArgh! fds[0] is NULL!");
while (p->fds[n].ptr !=0 && remaining>0 ) {
// if (n >= MAX_SWDS_ELEMS) DebugStr("\pOverflowing SWDS in while loop!");
swds[n].ptr = p->fds[n].ptr;
if ( p->fds[n].length > remaining) {
swds[n].length = remaining;
p->fds[n].length -= remaining;
p->fds[n].ptr += remaining;
remaining=0;
}
else
{
swds[n].length = p->fds[n].length;
remaining -= p->fds[n].length;
p->fds[n].length = 0;
p->fds[n].ptr = 0;
}
n++;
}
if (n>p->maxFDSused) p->maxFDSused=n;
compressfds( p->fds);
queued = nsend-remaining;
for(m=0; m<n; m++) {
#ifdef NET_DEBUG_MUCHINFO
sprintf(net_debug_string, "swds[m].ptr: %lx\tswds[m].length: %d", (unsigned int)swds[m].ptr, (int)swds[m].length);
net_debug_print(net_debug_string);
#endif
}
for (m=0; m<n; m++)
{
BlockMove(buffer, swds[m].ptr, swds[m].length); /* BYU LSC - Put data in WDS */
/*
* encrypt if encrypting the session
*/
if (p->aedata && ((tnParams *)p->aedata)->encrypting)
encrypt((tnParams *)p->aedata, (unsigned char *)swds[m].ptr, swds[m].length);
buffer=(void *)((char *)buffer + swds[m].length);
}
swds[m].ptr = 0L;
swds[m].length=0;
pbp=getPB( TCPd, TCPSend, p->stream, 2); /* Make send call */
pbp->pb.csParam.send.wdsPtr = (Ptr) swds;
pbp->pb.csParam.send.pushFlag = p->push;
pbp->pb.csParam.open.ulpTimeoutValue = (SInt8)gApplicationPrefs->SendTimeout;// timeout value
pbp->pb.csParam.open.ulpTimeoutAction = 1; // Abort
pbp->pb.csParam.open.validityFlags = 0xC0; // Timeout and action are valid
if (nextIsUrgent)
{
nextIsUrgent = FALSE;
pbp->pb.csParam.send.urgentFlag = TRUE;
}
p->push=0;
if ((err = xPBControlAsync(pbp, SendCompleteInitUPP)) != noError)
{
char temp_xvvyz[256];
sprintf(temp_xvvyz, "netwrite: %d", err);
DoError(510 | NET_ERRORCLASS, LEVEL2, temp_xvvyz);
return(-1);
}
return(queued);
}
/**************************************************************************/
/* Mnetpush
* attempt to push the rest of the data from the queue
* and then return whether the queue is empty or not (0 = empty)
* returns the number of bytes in the queue.
*/
short netpush(short pnum)
{
StreamRPtr p;
MyTCPpbPtr pbp;
short inQ;
OSErr err;
if (pnum < 0 || pnum >= NPORTS) /* BYU 2.4.15 */
return(-2);
if (NULL == (p = streams[pnum]))
return(-2);
pbp=getPB( TCPd, TCPStatus, p->stream, 3); /* Make status call */
//#ifdef NET_DEBUG_MUCHINFO
// sprintf(net_debug_string, "TCPd == %d", TCPd);
// net_debug_print(net_debug_string);
//#endif
if ((err = xPBControlSync(pbp)) != noError) { /* status call bombed */
char temp_xvvyz[256];
sprintf(temp_xvvyz, "netpush: %d", err);
DoError(509 | NET_ERRORCLASS, LEVEL2, temp_xvvyz);
}
inQ = pbp->pb.csParam.status.amtUnackedData;
MyPBreturn( pbp);
p->push=1;
return(inQ);
}
/**************************************************************************/
/* Mnetqlen
* return the number of bytes waiting to be read from the incoming queue.
*/
short netqlen(short pnum)
{
StreamRPtr p;
MyTCPpbPtr pbp;
short inQ;
if (pnum < 0 || pnum >= NPORTS) /* BYU 2.4.15 */
return(-2);
if (NULL == (p = streams[pnum]))
return(-2);
pbp=getPB( TCPd, TCPStatus, p->stream, 4); /* Make status call */
if (xPBControlSync(pbp) != noError) /* status call failed */
DoError(509 | NET_ERRORCLASS, LEVEL2, "Mnetqlen");
inQ = pbp->pb.csParam.status.amtUnreadData;
MyPBreturn( pbp);
p->push = 1;
return(inQ);
}
/**************************************************************************/
/* Mnetroom()
* return how much room is available in output buffer for a connection
*/
short netroom(short pnum)
{
StreamRPtr p;
short inQ, n;
if (pnum < 0 || pnum >= NPORTS) /* BYU 2.4.15 */
return(-2);
if (NULL == (p = streams[pnum]))
return(-2);
reclaim( p);
compressfds( p->fds);
#ifdef OLDM
pbp=getPB( TCPd, TCPStatus, p->stream, 5); /* Make status call */
if (xPBControlSync(pbp) != noError)
DoError(509 | NET_ERRORCLASS, LEVEL1, "Mnetroom");
inQ = pbp->csParam.status.sendWindow -
pbp->csParam.status.amtUnackedData;
MyPBreturn( pbp);
#else
/*#pragma unused(pbp) /* BYU LSC */
#endif
inQ = n = 0;
while (p->fds[n].ptr) {
inQ += p->fds[n].length; /* add up free list space */
n++;
}
return(inQ);
}
/**************************************************************************/
void netgetip(unsigned char *st)
{
struct GetAddrParamBlock mypb;
/* long netmask; */
net_debug_print("Attempting getmyipaddr");
NetWriteZero((Ptr)&mypb, sizeof(struct GetAddrParamBlock));
mypb.ioCRefNum = TCPd; /* BYU LSC - TCP driver has to be open by now */
mypb.csCode = ipctlGetAddr;
if (PBControl((ParmBlkPtr)&mypb, false) != noError)
{
DoError(511 | NET_ERRORCLASS, LEVEL2, NULL);
return;
}
BlockMove(&mypb.ourAddress, st, 4); /* BYU LSC - copy the address */
/* netmask is here if we want it, too */
}
void netfromport /* next "open" will use this port */
( short port)
{
nnfromport = (ip_port)port;
}
/**************************************************************************/
/* Mnetest?
* is a particular session established yet?
* Returns 0 if the connection is in the established state.
*/
short netest(short pnum)
{
StreamRPtr p;
MyTCPpbPtr pbp;
short inQ;
if (pnum < 0 || pnum >= NPORTS) /* BYU 2.4.15 */
return(-2);
if (NULL == (p = streams[pnum]))
return(-2);
pbp=getPB( TCPd, TCPStatus, p->stream, 6); /* Make status call */
if (xPBControlSync(pbp) != noError)
{
DoError(509 | NET_ERRORCLASS, LEVEL2, "Mnetest");
inQ = -1;
}
else
inQ = pbp->pb.csParam.status.connectionState !=8;
MyPBreturn( pbp);
return(inQ);
}
/**************************************************************************/
/* Mnetlisten
* Listen to a TCP port number and make the connection automatically when
* the SYN packet comes in. The TCP layer will notify the higher layers
* with a CONOPEN event. Save the port number returned to refer to this
* connection.
*
* usage: portnum = netlisten(service);
* short service;
*
*/
short netlisten(ip_port serv)
{
short pnum;
StreamRPtr p;
MyTCPpbPtr pbp;
pnum = makestream();
if (pnum < 0 || pnum >= NPORTS) /* BYU 2.4.15 */
return(-2);
if (NULL == (p = streams[pnum]))
return(-2);
pbp=getPB( TCPd, TCPPassiveOpen, p->stream, 8); /* Make Listen call */
pbp->pb.csParam.open.localPort = serv;
if (xPBControlAsync(pbp, OpenCompleteInitUPP) != noError)
DoError(513 | NET_ERRORCLASS, LEVEL2, NULL);
return(pnum); /* BYU 2.4.16 */
}
/***********************************************************************/
/* Mnetgetftp
* Provides the information that ftp needs to open a stream back to the
* originator of the command connection. The other side's IP number
* and the port numbers to be used to calculate the default data connection
* number. Returns values in an integer array for convenient use in
* PORT commands.
*/
short netgetftp(short pnum, ip_addr *addr, ip_port *localPort, ip_port *remotePort)
{
StreamRPtr p;
MyTCPpbPtr pbp;
if (pnum < 0)
return(-2);
if (NULL == (p = streams[pnum]))
return(-2);
pbp=getPB( TCPd, TCPStatus, p->stream, 9); /* Make status call */
if (xPBControlSync(pbp) != noError)
DoError(514 | NET_ERRORCLASS, LEVEL2, NULL);
*addr = pbp->pb.csParam.status.remoteHost;
*localPort = pbp->pb.csParam.status.localPort;
*remotePort = pbp->pb.csParam.status.remotePort;
MyPBreturn( pbp);
return 0;
}
/**************************************************************************/
/* Open a network socket for the user. */
short netxopen( ip_addr machine, ip_port service,
short timeout ) // in seconds
{
short pnum;
StreamRPtr p;
MyTCPpbPtr pbp;
pnum = makestream();
if (pnum < 0)
return(-2);
if (NULL == (p = streams[pnum]))
return(-2);
pbp=getPB( TCPd, TCPActiveOpen, p->stream, 10); /* Make Listen call */
pbp->pb.csParam.open.remoteHost = machine; /* IP # */
pbp->pb.csParam.open.remotePort = service; /* Port */
pbp->pb.csParam.open.localPort = nnfromport; /* My Port */
pbp->pb.csParam.open.ulpTimeoutValue = (SInt8)timeout; // timeout value
pbp->pb.csParam.open.ulpTimeoutAction = 1; // Abort
pbp->pb.csParam.open.validityFlags = 0xC0; // Timeout and action are valid
nnfromport=0; /* Next one is random */
if (xPBControlAsync(pbp, OpenCompleteInitUPP) != noError) {
DoError(515 | NET_ERRORCLASS, LEVEL2, NULL);
return(-1);
}
SetPortType(pnum, NO_TYPE); // Is allocated to the user
#ifdef NET_DEBUG
sprintf(net_debug_string, "TCPOpen on port #%d", pnum);
net_debug_print(net_debug_string);
#endif
return(pnum); /* BYU 2.4.16 */
}
/**************************************************************************/
/* Mnetclose
* Do appropriate actions to return connection state to SCLOSED which
* enables the memory for that port to be reused.
*
* Specifically:
* o If status is closed, then release the data structures
* o If status is not close, perform bkgrd close which generates CLOSEDONE,
* which should make the session layer call us again
*/
short netclose(short pnum)
{
StreamRPtr p;
MyTCPpbPtr pbp;
OSErr errorCode;
short status;
static short count=0;
errorCode = 0;
if (pnum < 0 || pnum >= NPORTS) /* is a valid port? */
return(-1);
if ((p = streams[pnum]) == NULL) /* nothing there */
return (1);
pbp=getPB( TCPd, TCPStatus, p->stream, 11); /* Make status call */
if ((errorCode = xPBControlSync(pbp)) != noError)
{
if ( errorCode == invalidStreamPtr)
{
DoError (516 | NET_ERRORCLASS, LEVEL2, "Mnetclose");
return(-1);
}
else
{
status=0;
count =0;
}
}
else
{
status = pbp->pb.csParam.status.connectionState; /* The connection Status */
if (count++ ==10)
{
status= 0;
count =0;
}
}
#ifdef NET_DEBUG
sprintf(net_debug_string, "Mnetclose:error code=%i status=%d",(int)errorCode, status);
net_debug_print(net_debug_string);
#endif
if (status < 18 && status >2 ) { /* We aren't closed yet ! */
#ifdef NET_DEBUG
sprintf(net_debug_string, "TCPClose being attempted state ...[%d]",status); /* Prolly because outstanding close */
net_debug_print(net_debug_string);
#endif
clearPB( pbp, TCPd, TCPClose, p->stream); /* Make Close call */
if ((errorCode=xPBControlAsync(pbp, CloseCompleteInitUPP)) != noError)
{ /* TCP close failed */
DoError(517 | NET_ERRORCLASS, LEVEL2, "Mnetclose");
return (errorCode);
}
/* Go ahead and return... PB is in use by Async Close call. */
return (0); /* Return with OK */
}
/* IF we got here, we must be at closed state, so free memory */
#ifdef NET_DEBUG
sprintf(net_debug_string, "TCP being released, status = %d", status);
net_debug_print(net_debug_string);
#endif
clearPB( pbp,TCPd, TCPRelease, p->stream); /* Make Release call */
if (xPBControlSync(pbp) != noError)
{ /* TCP failed to be released. Let us know... */
DoError (518 | NET_ERRORCLASS, LEVEL2, "Mnetclose");
return (-1);
}
DisposPtr( p->buffer); /* Free Receive Buffer */
DisposPtr( p->sbuffer); /* Free Send Buffer */
DisposPtr((Ptr) p); /* Free Stream Structure */
streams[pnum]=0L;
netportencryptstate(pnum, 0);
MyPBreturn(pbp);
return(0);
}
/**************************************************************************/
/* Nuke the connection, NOW! */
short netabort(short pnum)
{
StreamRPtr p;
MyTCPpbPtr pbp;
OSErr errorCode = noErr;
if (pnum < 0 || pnum >= NPORTS) /* is a valid port? */
return(-1);
if ((p = streams[pnum]) != NULL) /* something there */
{
pbp=getPB( TCPd, TCPAbort, p->stream, 12); /* Make Close call */
if ((errorCode=xPBControlSync(pbp)) != noError) /* TCP abort failed. Bad news */
DoError (519 | NET_ERRORCLASS, LEVEL1, NULL);
clearPB( pbp,TCPd, TCPRelease, p->stream); /* Make Close call */
if (xPBControlSync(pbp) != noError)
{
DoError (518 | NET_ERRORCLASS, LEVEL2, NULL);
return(-1);
}
}
else
return(1);
DisposPtr( p->buffer); /* Free Receive Buffer */
DisposPtr( p->sbuffer); /* Free Send Buffer */
DisposPtr((Ptr) p); /* Free Stream Structure */
streams[pnum]=0L;
MyPBreturn(pbp);
return(0);
}
/**************************************************************************/
/* Mnetinit
* Calls all of the various initialization routines that set up queueing
* variables, static values, reads configuration files, etc.
*/
void Mnetinit( void)
{
short i;
OSErr err;
#ifndef __powerpc__
MyA5 = SetCurrentA5();
#endif
for (i=0; i<NPORTS;i++) {
streams[i]= (StreamRPtr) 0;
}
gFreePBQueue.qHead = NULL;
gFreePBQueue.qTail = NULL;
gFreePBQueue.qFlags = 0;
gFreeSWDSQueue.qHead = NULL;
gFreeSWDSQueue.qTail = NULL;
gFreeSWDSQueue.qFlags = 0;
if ((err = OpenDriver("\p.IPP",&TCPd)) != noError) /* cant open the IP driver */
{
SetCursor(theCursors[normcurs]);
FatalAlert(CANT_OPEN_MACTCP, 300, err); // Doesn't return!
}
}
/*************************************************************************/
/* Mnetshut
* Close all the connections and turn off the hardware.
*/
void netshut(void)
{
short i;
for (i=0; i < NPORTS ; i++)
if (streams[i] != (StreamRPtr) NULL)
netabort(i); /* Prolly should abort */
}
/**************************************************************************/
short findbystream(StreamPtr streamPtr)
{
short pnum=0;
while (pnum<NPORTS &&
( (streams[pnum] ==(StreamRPtr)0L) || (streamPtr !=streams[pnum]->stream)))
pnum++;
if (pnum >=NPORTS)
return(-1);
else
return(pnum);
}
/**************************************************************************/
pascal void Notify(StreamPtr streamPtr, unsigned short code, Ptr uptr,
unsigned short terminReason, struct ICMPReport *icmpMsg)
{
UNUSED_ARG(uptr)
UNUSED_ARG(terminReason)
UNUSED_ARG(icmpMsg)
StreamRPtr p;
short pnum;
pnum = findbystream(streamPtr);
if (pnum < 0 || (p = streams[pnum]) == 0L)
return;
switch( code) {
case TCPTerminate:
case TCPClosing:
netputevent(CONCLASS, CONCLOSE, pnum,0);
break;
case TCPULPTimeout:
netputevent(CONCLASS, CONFAIL, pnum,0);
break;
case TCPDataArrival:
case TCPUrgent:
netputuev(CONCLASS, CONDATA, pnum,0);
break;
case TCPICMPReceived:
default:
break;
}
return;
}
/**************************************************************************/
static void OpenCompleteInit(TCPiopb *pbp)
{
long saveA5;
MyTCPpbPtr myptr;
myptr = (MyTCPpbPtr)pbp;
#ifndef _powerpc_
saveA5 = SetA5(myptr->SavedA5);
#endif
OpenComplete(myptr);
#ifndef _powerpc_
SetA5(saveA5);
#endif
}
/**************************************************************************/
void OpenComplete(MyTCPpbPtr pbp)
{
StreamRPtr p;
short pnum;
pnum= findbystream(pbp->pb.tcpStream);
if (pnum < 0 || (p = streams[pnum]) == 0L) {
MyPBreturn(pbp); //BUGG: Shouldn't we return here so we don't MyPBreturn twice?
return; //I'll assume so (CCP)
}
if (pbp->pb.ioResult !=noError)
netputevent(CONCLASS, CONFAIL, pnum,pbp->pb.ioResult); /* Failure ... */
else
netputevent(CONCLASS, CONOPEN, pnum,0); /* Success ! */
MyPBreturn( pbp);
}
/**************************************************************************/
void SendComplete(MyTCPpbPtr pbp)
{
StreamRPtr p;
short pnum;
wdsEntry *swds;
swds = (wdsEntry *) pbp->pb.csParam.send.wdsPtr;
pnum = findbystream(pbp->pb.tcpStream);
if (pnum < 0 || (p = streams[pnum]) == 0L) {
MyPBreturn(pbp);
return;
}
MyPBreturn( pbp);
giveback( p, (wdsEntry *) pbp->pb.csParam.send.wdsPtr); /* BYU LSC - Give this back.... NOW */
returnSWDS( swds);
}
/**************************************************************************/
static void SendCompleteInit(TCPiopb *pbp)
{
long saveA5;
MyTCPpbPtr myptr;
myptr = (MyTCPpbPtr)pbp;
#ifndef _powerpc_
saveA5 = SetA5(myptr->SavedA5);
#endif
SendComplete(myptr);
#ifndef _powerpc_
SetA5(saveA5);
#endif
}
/**************************************************************************/
void CloseComplete(MyTCPpbPtr pbp)
{
StreamRPtr p;
short pnum;
pnum= findbystream(pbp->pb.tcpStream);
if (pnum < 0 || (p = streams[pnum]) == 0L)
{
netputevent(SCLASS, CLOSEDONE+1, pnum,0);
MyPBreturn(pbp);
return;
}
if (pbp->pb.ioResult !=noError)
netputevent(SCLASS, CLOSEDONE+1, pnum,0);
else
netputevent(SCLASS, CLOSEDONE, pnum,0); /* Success ! */
MyPBreturn( pbp);
}
/**************************************************************************/
static void CloseCompleteInit(TCPiopb *pbp)
{
long saveA5;
MyTCPpbPtr myptr;
myptr = (MyTCPpbPtr)pbp;
#ifndef _powerpc_
saveA5 = SetA5(myptr->SavedA5);
#endif
CloseComplete(myptr);
#ifndef _powerpc_
SetA5(saveA5);
#endif
}
short netportencryptstate (short port, Ptr edata)
{
StreamRPtr p;
if (port < 0 || port >= NPORTS)
return(-2);
if ((p = streams[port]) == NULL)
return(-2);
p->aedata = edata;
return 0;
}
void networkUPPinit(void)
{
OpenCompleteInitUPP = NewTCPIOCompletionProc(OpenCompleteInit);
CloseCompleteInitUPP = NewTCPIOCompletionProc(CloseCompleteInit);
SendCompleteInitUPP = NewTCPIOCompletionProc(SendCompleteInit);
NotifyUPP = NewTCPNotifyProc(Notify);
}